package cn.janyd.common.core.vo;

import cn.janyd.common.core.constants.GlobalErrorCodeConstants;
import cn.janyd.common.core.exception.GlobalException;
import cn.janyd.common.core.exception.ServiceException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.util.function.Consumer;

/**
 * @author janyd
 * @since 2020/8/5 11:28
 */
@Data
@Accessors(chain = true)
public class CommonResult<T> implements Serializable {

    /**
     * 错误码
     */
    private Integer code;

    /**
     * 数据
     */
    private T data;

    /**
     * 错误信息，用户可阅读
     */
    private String message;

    /**
     * 错误明细，用于内部调试错误
     */
    private String detailMessage;

    /**
     * 基础构造函数,私有内部调用
     *
     * @param code          错误码
     * @param data          返回数据
     * @param message       错误信息
     * @param detailMessage 错误详细信息
     */
    private CommonResult(Integer code, T data, String message, String detailMessage) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.detailMessage = detailMessage;
    }

    /**
     * 错误信息构造函数
     *
     * @param code    错误码
     * @param message 错误信息
     */
    private CommonResult(Integer code, String message) {
        this(code, message, "");
    }

    /**
     * 错误信息构造函数 (详细)
     *
     * @param code    错误码
     * @param message 错误信息
     */
    private CommonResult(Integer code, String message, String detailMessage) {
        this(code, null, message, detailMessage);
    }

    /**
     * 成功构造函数
     *
     * @param data 返回数据
     */
    private CommonResult(T data) {
        this(GlobalErrorCodeConstants.SUCCESS, data, null, null);
    }

    /**
     * 是否成功
     */
    @JsonIgnore
    public boolean isSuccess() {
        return GlobalErrorCodeConstants.SUCCESS == this.code;
    }

    public String codeStr() {
        return String.valueOf(this.code);
    }

    /**
     * 如果成功则执行回调
     *
     * @param consumer 回调对象
     */
    public CommonResult<T> ifSuccess(Consumer<? super T> consumer) {
        if (isSuccess() && data != null) {
            consumer.accept(data);
        }
        return this;
    }

    /**
     * 如果失败则回调
     *
     * @param consumer 回调对象
     */
    public CommonResult<T> ifFail(Consumer<Integer> consumer) {
        if (!isSuccess()) {
            consumer.accept(this.code);
        }
        return this;
    }

    /**
     * 判断是否有异常，有则抛出
     */
    public void checkError() {
        if (isSuccess()) {
            return;
        }

        // 全局异常
        if (GlobalErrorCodeConstants.isMatch(code)) {
            throw new GlobalException(code, message).setDetailMessage(detailMessage);
        }
        // 业务异常
        throw new ServiceException(code, message).setDetailMessage(detailMessage);
    }

    /**
     * 如果成功则获取数据，如果未成功则抛出异常
     *
     * @return 数据
     */
    @JsonIgnore
    public T getOrThrow() {
        if (isSuccess()) {
            return this.data;
        }

        // 全局异常
        if (GlobalErrorCodeConstants.isMatch(code)) {
            throw new GlobalException(code, message).setDetailMessage(detailMessage);
        }
        // 业务异常
        throw new ServiceException(code, message).setDetailMessage(detailMessage);
    }

    /**
     * 成功返回对象
     */
    public static <T> CommonResult<T> success(T data) {
        return new CommonResult<>(data);
    }

    /**
     * 错误，返回对象
     */
    public static <T> CommonResult<T> error(Integer code, String message, String detailMessage) {
        return new CommonResult<>(code, message, detailMessage);
    }

    /**
     * 错误，返回对象
     */
    public static <T> CommonResult<T> error(Integer code, String message) {
        return error(code, message, null);
    }

    public static <T> CommonResult<T> error(ServiceException serviceException) {
        return error(serviceException.getCode(), serviceException.getMessage(), serviceException.getDetailMessage());
    }

    public static <T> CommonResult<T> error(GlobalException globalException) {
        return error(globalException.getCode(), globalException.getMessage(), globalException.getDetailMessage());
    }


}
